using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

public class MapGenerator : MonoBehaviour
{
   [Header("地图配置文件")]
   public MapConfigSO mapConfigSO;
   [Header("房间预制体")]
   public Room roomPrefab;
   [Header("线段预制体")]
   public LineRenderer linePrefab;
   [Header("房间布局数据")]
   public MapLayoutSO mapLayout;
   [Header("屏幕高度")]
   private float screenHeight;
   [Header("屏幕宽度")]
   private float screemWidth;
   [Header("列宽")]
   private float columnWidth;
   [Header("生成点")]
   private Vector3 generatePoint;
   [Header("预留的边界")]
   [SerializeField]private float border;
   [Header("房间列表")]
   private List<Room> rooms = new();
   [Header("连线列表")]
   private List<LineRenderer> lines = new();
   [Header("所有房间数据列表")]
   public List<RoomDataSO> roomDataList = new();
   [Header("房间数据字典")]
   private Dictionary<RoomType, RoomDataSO> roomDataDict = new();
   
   private void Awake()
   {
      //获取屏幕高度
      screenHeight = Camera.main.orthographicSize * 2;
      //获取屏幕宽度
      screemWidth = screenHeight * Camera.main.aspect;
      //计算列宽
      columnWidth = screemWidth / (mapConfigSO.roomBuleprints.Count + 1);
      //columnWidth = screemWidth / (mapConfigSO.roomBuleprints.Count);
      
      //将房间数据列表存入字典
      foreach (var roomDataSo in roomDataList)
      {
         roomDataDict.Add(roomDataSo.roomType, roomDataSo);
      }
   }

   // private void Start()
   // {
   //    CreatMap();
   // }
   private void OnEnable()
   {
      if(mapLayout.mapRoomDataList.Count > 0)
         LoadMap();
      else
         CreatMap();
   }

   /// <summary>
   /// 创建地图
   /// </summary>
   public void CreatMap()
   {
      //创建前一列房间列表
      List<Room> previousColumnRooms = new List<Room>();
      
      for (int column = 0; column < mapConfigSO.roomBuleprints.Count; column++)
      {
         //获取蓝图中的数据
         var buleprint = mapConfigSO.roomBuleprints[column];
         //获取房间数量
         var amount = Random.Range(buleprint.min, buleprint.max);
         //获取生成点的Y坐标
         var startHeight = screenHeight / 2 - screenHeight / (amount + 1);
         //赋值生成点
         generatePoint = new Vector3(-screemWidth / 2 + border + columnWidth * column, startHeight, 0);
         //赋值生成点坐标
         var newPosition = generatePoint;

         //创建当前列房间列表
         List<Room> currentColumnRooms = new List<Room>();
         
         
         var roomGapY = screenHeight / (amount + 1);
         //循环当前列的所有房间数量生成房间
         for (int i = 0; i < amount; i++)
         {
            //如果是最后一列，Boss房间，固定生成点
            if (column == mapConfigSO.roomBuleprints.Count - 1)
               newPosition.x = screemWidth / 2 - border * 2;
            //如果不是第一列，生成点坐标x轴随机偏移
            else if (column != 0)
               newPosition.x = generatePoint.x + Random.Range(-border / 2, border / 2);
            
            newPosition.y = generatePoint.y - roomGapY * i;
            //生成房间
            var room = Instantiate(roomPrefab, newPosition, Quaternion.identity, transform);
            RoomType newType = GetRandomRoomType(mapConfigSO.roomBuleprints[column].roomType);
            
            //设置只有第一列的房间可以进入，其他列的房间不可进入
            if (column == 0)
               room.roomState = RoomState.Attainable;
            else
               room.roomState = RoomState.Locked;
            
            
            room.SetupRoom(column, i, GetRoomData(newType));
            
            rooms.Add(room);
            currentColumnRooms.Add(room);
         }
         
         //如果不是第一列，如果不是则连接到前一列
         if (previousColumnRooms.Count > 0)
         {
            //创建两个列表的连线
            CreateColumnConnection(previousColumnRooms, currentColumnRooms);
         }
         
         previousColumnRooms = currentColumnRooms;
         
      }
      SaveMap();
   }

   /// <summary>
   /// 创建两个列表的连线
   /// </summary>
   /// <param name="previousColumnRooms"></param>
   /// <param name="currentColumnRooms"></param>
   private void CreateColumnConnection(List<Room> column1, List<Room> column2)
   {
      HashSet<Room> connectedColumn2Rooms = new HashSet<Room>();

      //进行连线
      foreach (var room in column1)
      {
         var targetRoom = connectedToRandomRoom(room, column2,false);
         connectedColumn2Rooms.Add(targetRoom);
      }
      //如果有房间没有被连接到
      foreach (var room in column2)
      {
         if(!connectedColumn2Rooms.Contains(room))
            connectedToRandomRoom(room, column1,true);
      }
   }

   /// <summary>
   /// 随机连接到一个房间
   /// </summary>
   /// <param name="room"></param>
   /// <param name="column2"></param>
   /// <exception cref="NotImplementedException"></exception>
   private Room connectedToRandomRoom(Room room, List<Room> column2,bool check)
   {
      Room targetRoom;
      
      targetRoom = column2[Random.Range(0, column2.Count)];

      if (check)
      {
         targetRoom.linkTo.Add(new(room.column, room.line));
      }
      else
      {
         room.linkTo.Add(new(targetRoom.column, targetRoom.line));
      }
      
      //创建连线
      var line = Instantiate(linePrefab, transform);
      line.SetPosition(0, room.transform.position);
      line.SetPosition(1, targetRoom.transform.position);

      lines.Add(line);
      return targetRoom;
   }

   //重新生成地图
   [ContextMenu("ReGenerateRoom")]
   public void ReGenerateRoom()
   {
      foreach (var room in rooms)
      {
         Destroy(room.gameObject);
      }
      foreach (var line in lines)
      {
         Destroy(line.gameObject);
      }
      rooms.Clear();
      lines.Clear();
      CreatMap();
   }
   
   //返回房间数据
   private RoomDataSO GetRoomData(RoomType roomType)
   {
      return roomDataDict[roomType];
   }
   
   private RoomType GetRandomRoomType(RoomType flags)
   {
      string[] options = flags.ToString().Split(',');
      
      string randomOption = options[Random.Range(0, options.Length)];
      
      RoomType randomRoomType = (RoomType) Enum.Parse(typeof(RoomType), randomOption);
      return randomRoomType;
   }

   private void SaveMap()
   {
      mapLayout.mapRoomDataList = new();

      //遍历所有房间，将房间数据存入地图数据
      for (var i = 0; i < rooms.Count; i++)
      {
         var room = new MapRoomData()
         {
            posX = rooms[i].transform.position.x,
            posY = rooms[i].transform.position.y,
            column = rooms[i].column,
            line = rooms[i].line,
            roomData = rooms[i].roomDataSO,
            roomState = rooms[i].roomState,
            linkTo = rooms[i].linkTo
         };
         mapLayout.mapRoomDataList.Add(room);
      }
      
      mapLayout.mapLineData = new();
      //添加连线数据
      for (var i = 0; i < lines.Count; i++)
      {
         var line = new LinePositon()
         {
            startPos = new SerializableVector3(lines[i].GetPosition(0)),
            endPos = new SerializableVector3(lines[i].GetPosition(1)),
         };
         
         mapLayout.mapLineData.Add(line);
      }
   }
   private void LoadMap()
   {
      //读取地图数据，生成房间
      for (var i = 0; i < mapLayout.mapRoomDataList.Count; i++)
      {
         var newPos = new Vector3(mapLayout.mapRoomDataList[i].posX, mapLayout.mapRoomDataList[i].posY, 0);
         var newRoom = Instantiate(roomPrefab, newPos, Quaternion.identity, transform); 
         newRoom.roomState = mapLayout.mapRoomDataList[i].roomState;
         newRoom.SetupRoom(mapLayout.mapRoomDataList[i].column, mapLayout.mapRoomDataList[i].line, mapLayout.mapRoomDataList[i].roomData);
         newRoom.linkTo = mapLayout.mapRoomDataList[i].linkTo;
         
         rooms.Add(newRoom);
      }
      
      //读取地图数据，生成连线
      for (var i = 0; i < mapLayout.mapLineData.Count; i++)
      {
         var newLine = Instantiate(linePrefab, transform);
         newLine.SetPosition(0, mapLayout.mapLineData[i].startPos.ToVector3());
         newLine.SetPosition(1, mapLayout.mapLineData[i].endPos.ToVector3());
         
         lines.Add(newLine);
      }
   }
}
